home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / edit / tde40.zip / tab.c < prev    next >
C/C++ Source or Header  |  1994-06-05  |  28KB  |  956 lines

  1. /*
  2.  * Most of the tab routines were gathered into one file.  There is an
  3.  * assembly routine tdeasm.c that expands tabs.  That routine is in
  4.  * assembly to keep screen updates fairly fast.
  5.  *
  6.  * The basic detab and entab algorithms were supplied by Dave Regan,
  7.  *   regan@jacobs.cs.orst.edu
  8.  *
  9.  * For more info on tabs see:
  10.  *
  11.  *     Brian W. Kernighan and P. J. Plauger, _Software Tools_, Addison-
  12.  *     Wesley Publishing Company, Reading, Mass, 1976, pp 18-27 and 35-39,
  13.  *     ISBN 0-20103669-X.
  14.  *
  15.  * The above reference gives info on fixed and variable tabs.  But when
  16.  *  it comes to non-fixed tabs, I prefer "smart" tabs.  Being lazy, I find
  17.  *  it more convenient to let the editor figure variable tabs for me.
  18.  *
  19.  *
  20.  * New editor name:  TDE, the Thomson-Davis Editor.
  21.  * Author:           Frank Davis
  22.  * Date:             June 5, 1991, version 1.0
  23.  * Date:             July 29, 1991, version 1.1
  24.  * Date:             October 5, 1991, version 1.2
  25.  * Date:             January 20, 1992, version 1.3
  26.  * Date:             February 17, 1992, version 1.4
  27.  * Date:             April 1, 1992, version 1.5
  28.  * Date:             June 5, 1992, version 2.0
  29.  * Date:             October 31, 1992, version 2.1
  30.  * Date:             April 1, 1993, version 2.2
  31.  * Date:             June 5, 1993, version 3.0
  32.  * Date:             August 29, 1993, version 3.1
  33.  * Date:             November 13, 1993, version 3.2
  34.  * Date:             June 5, 1994, version 4.0
  35.  *
  36.  * This program is released into the public domain, Frank Davis.
  37.  *   You may distribute it freely.
  38.  */
  39.  
  40. #include "tdestr.h"
  41. #include "common.h"
  42. #include "tdefunc.h"
  43. #include "define.h"
  44.  
  45.  
  46. /*
  47.  * Name:    tab_key
  48.  * Purpose: To make the necessary changes after the user types the tab key.
  49.  * Date:    June 5, 1991
  50.  * Passed:  window:  pointer to current window
  51.  * Notes:   If in insert mode, then this function adds the required
  52.  *           number of spaces in the file.
  53.  *          If not in insert mode, then tab simply moves the cursor right
  54.  *           the required distance.
  55.  */
  56. int  tab_key( TDE_WIN *window )
  57. {
  58. int  spaces;    /* the spaces to move to the next tab stop */
  59. char *source;   /* source for block move to make room for c */
  60. char *dest;     /* destination for block move */
  61. int  pad;
  62. int  len;
  63. register int rcol;
  64. int  old_bcol;
  65. register TDE_WIN *win;   /* put window pointer in a register */
  66. int  rc;
  67.  
  68.    win  = window;
  69.    if (win->ll->len  ==  EOF)
  70.       return( OK );
  71.    rcol = win->rcol;
  72.    old_bcol = win->bcol;
  73.    show_ruler_char( win );
  74.    /*
  75.     * work out the number of spaces to the next tab stop
  76.     */
  77.    if (mode.smart_tab)
  78.       spaces = next_smart_tab( win );
  79.    else
  80.       spaces = mode.ltab_size - (rcol % mode.ltab_size);
  81.  
  82.    assert( spaces >= 0 );
  83.    assert( spaces < MAX_LINE_LENGTH );
  84.  
  85.    rc = OK;
  86.    if (mode.insert && rcol + spaces < g_display.line_length) {
  87.       copy_line( win->ll );
  88.       detab_linebuff( );
  89.  
  90.       /*
  91.        * work out how many characters need to be inserted
  92.        */
  93.       len = g_status.line_buff_len;
  94.       pad = rcol > len ? rcol - len : 0;
  95.       if (len + pad + spaces >= g_display.line_length) {
  96.          /*
  97.           *  line too long to add
  98.           */
  99.          error( WARNING, win->bottom_line, ed1 );
  100.          rc = ERROR;
  101.          g_status.copied = FALSE;
  102.       } else {
  103.          if (pad > 0  || spaces > 0) {
  104.             source = g_status.line_buff + rcol - pad;
  105.             dest = source + pad + spaces;
  106.  
  107.             assert( len + pad - rcol >= 0 );
  108.             assert( len + pad - rcol < MAX_LINE_LENGTH );
  109.  
  110.             memmove( dest, source, len + pad - rcol );
  111.  
  112.             /*
  113.              * if padding was required, then put in the required spaces
  114.              */
  115.  
  116.             assert( pad + spaces >= 0 );
  117.             assert( pad + spaces < MAX_LINE_LENGTH );
  118.  
  119.             memset( source, ' ', pad + spaces );
  120.             g_status.line_buff_len += pad + spaces;
  121.             entab_linebuff( );
  122.          }
  123.  
  124.          win->ll->dirty = TRUE;
  125.          win->file_info->dirty = GLOBAL;
  126.          show_changed_line( win );
  127.          rcol += spaces;
  128.          win->ccol += spaces;
  129.       }
  130.    } else if (rcol + spaces <= g_display.line_length) {
  131.       /*
  132.        * advance the cursor without changing the text underneath
  133.        */
  134.       rcol += spaces;
  135.       win->ccol += spaces;
  136.    }
  137.    check_virtual_col( win, rcol, win->ccol );
  138.    if (old_bcol != win->bcol) {
  139.       make_ruler( win );
  140.       show_ruler( win );
  141.    }
  142.    return( rc );
  143. }
  144.  
  145.  
  146. /*
  147.  * Name:    backtab
  148.  * Purpose: To make the necessary changes after the user presses the backtab.
  149.  * Date:    November 1, 1991
  150.  * Passed:  window:  pointer to current window
  151.  * Notes:   If in insert mode, then this function subs the required
  152.  *           number of spaces in the file.
  153.  *          If not in insert mode, then tab simply moves the cursor left
  154.  *           the required distance.
  155.  */
  156. int  backtab( TDE_WIN *window )
  157. {
  158. int  spaces;    /* the spaces to move to the next tab stop */
  159. char *source;   /* source for block move to make room for c */
  160. char *dest;     /* destination for block move */
  161. int  pad;
  162. int  len;
  163. register int rcol;
  164. int  old_bcol;
  165. register TDE_WIN *win;   /* put window pointer in a register */
  166.  
  167.    win  = window;
  168.    rcol = win->rcol;
  169.    if (win->ll->len == EOF || win->rcol == 0)
  170.       return( OK );
  171.    old_bcol = win->bcol;
  172.    show_ruler_char( win );
  173.  
  174.    /*
  175.     * work out the number of spaces to the previous tab stop
  176.     */
  177.    if (mode.smart_tab)
  178.       spaces = prev_smart_tab( win );
  179.    else
  180.       spaces = win->rcol % mode.ltab_size;
  181.  
  182.    if (spaces == 0)
  183.       spaces = mode.ltab_size;
  184.    copy_line( win->ll );
  185.    detab_linebuff( );
  186.    len = g_status.line_buff_len;
  187.    if (mode.insert && rcol - spaces < len) {
  188.       pad = rcol > len ? rcol - len : 0;
  189.       if (pad > 0  || spaces > 0) {
  190.          /*
  191.           * if padding was required, then put in the required spaces
  192.           */
  193.          if (pad > 0) {
  194.  
  195.             assert( rcol - pad >= 0 );
  196.             assert( pad < MAX_LINE_LENGTH );
  197.  
  198.             source = g_status.line_buff + rcol - pad;
  199.             dest = source + pad;
  200.  
  201.             assert( pad >= 0 );
  202.             assert( pad < MAX_LINE_LENGTH );
  203.  
  204.             memmove( dest, source, pad );
  205.             memset( source, ' ', pad );
  206.             g_status.line_buff_len += pad;
  207.          }
  208.          source = g_status.line_buff + rcol;
  209.          dest = source - spaces;
  210.  
  211.          assert( len + pad - rcol >= 0 );
  212.          assert( len + pad - rcol < MAX_LINE_LENGTH );
  213.  
  214.          memmove( dest, source, len + pad - rcol );
  215.          g_status.line_buff_len -= spaces;
  216.          entab_linebuff( );
  217.       }
  218.  
  219.       win->ll->dirty = TRUE;
  220.       win->file_info->dirty = GLOBAL;
  221.       show_changed_line( win );
  222.       rcol -= spaces;
  223.       win->ccol -= spaces;
  224.    } else {
  225.       /*
  226.        * move the cursor without changing the text underneath
  227.        */
  228.       rcol -= spaces;
  229.       if (rcol < 0)
  230.          rcol = 0;
  231.       win->ccol -= spaces;
  232.    }
  233.    check_virtual_col( win, rcol, win->ccol );
  234.    if (old_bcol != win->bcol) {
  235.       make_ruler( win );
  236.       show_ruler( win );
  237.    }
  238.    return( OK );
  239. }
  240.  
  241.  
  242. /*
  243.  * Name:    next_smart_tab
  244.  * Purpose: To find next smart tab
  245.  * Date:    June 5, 1992
  246.  * Passed:  window: pointer to the current window
  247.  * Notes:   To find a smart tab 1) find the first non-blank line above the
  248.  *            current line, 2) find the first non-blank character after
  249.  *            column of the cursor.
  250.  */
  251. int  next_smart_tab( TDE_WIN *window )
  252. {
  253. register int spaces;    /* the spaces to move to the next tab stop */
  254. text_ptr s;             /* pointer to text */
  255. line_list_ptr ll;
  256. register TDE_WIN *win;   /* put window pointer in a register */
  257. int  len;
  258.  
  259.    /*
  260.     * find first previous non-blank line above the cursor.
  261.     */
  262.    win = window;
  263.    ll = win->ll->prev;
  264.    while (ll != NULL  && is_line_blank( ll->line, ll->len ))
  265.       ll = ll->prev;
  266.  
  267.    if (ll != NULL) {
  268.       s = ll->line;
  269.       /*
  270.        * if cursor